// any 类型与任何类型的交叉都是 any，也就是 1 & any 结果是 any。
type IsAny<T> = 's' extends ('d' & T) ? true : false

// any 在条件类型中也比较特殊，如果类型参数为 any，
// 会直接返回 trueType 和 falseType 的合并
type TestAny<T> = T extends number ? 1 : 2;

// 判断相等
// 避免无法这样判断any的情况
// type IsEqual<A, B> = (A extends B ? true : false) & (B extends A ? true : false);
type IsEqual2<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
    ? true : false;

// 判断是否为never
// never 在条件类型中也比较特殊，如果条件类型左边是类型参数，
// 并且传入的是 never，那么直接返回 never
// type TestNever<T> = T extends number ? 1 : 2;
// 不要直接使用never去判断就可以了
type IsNever<T> = [T] extends [never] ? true : false

// 判断是否为元组
// 元组类型也是数组类型，但每个元素都是只读的，
// 并且元组的length是数字字面量，而数组的 length 是 number

type arr = [1,2,3]['length']

type tuple = number[]['length']

type NotEqual<A, B> = 
(<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
? false : true;

type IsTuple<T> = T extends readonly [...params: infer Eles]
? NotEqual<Eles['length'], number>
: false

type IsTupleRes = IsTuple<[1,2]>
type IsNotTupleRes = IsTuple<number[]>


// 联合类型转交叉
// 函数参数的逆变性质一般就联合类型转交叉类型会用，记住就行
type UnionToIntersection<U> = 
(U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown
? R
: never

type UnionToIntersectionRes = UnionToIntersection<{xie: 1}|{bang: 2}>

// 提取索引类型的可选索引
// {} extends Pick<Obj, Key> 就能过滤出可选索引。（可选的意思就是有或者没有，没有的时候就是空的索引类型）
type GetOptional<Obj extends  Record<string, any>> = {
  [
      Key in keyof Obj 
          as {} extends Pick<Obj, Key> ? Key : never
  ] : Obj[Key];
}

// 提取索引类型的非可选索引
type isRequired<Key extends keyof Obj, Obj> = 
    {} extends Pick<Obj, Key> ? never : Key;

type GetRequired<Obj extends Record<string, any>> = { 
    [Key in keyof Obj as isRequired<Key, Obj>]: Obj[Key] 
}

// 索引类型可能有索引，也可能有可索引签名。
// sleep 是具体的索引
// [key: string]: any 就是可索引签名
// 索引是 string 类型，而可索引签名的不是
type Dong = {
  [key: string]: any;
  sleep(): void;
}


// 滤掉可索引签名
type RemoveIndexSignature<Obj extends Record<string, any>> = {
  [
      Key in keyof Obj 
          as Key extends `${infer Str}`? Str : never
  ]: Obj[Key]
}

// 取出class 的 public属性
// keyof 只能拿到 class 的 public 索引，private 和 protected 的索引会被忽略
class Xie {
  public name: string;
  protected age: number;
  private hobbies: string[];

  constructor() {
    this.name = 'dong';
    this.age = 20;
    this.hobbies = ['sleep', 'eat'];
  }
}
type ClassPublicProps<Obj extends Record<string, any>> = {
  [Key in keyof Obj]: Obj[Key]    
}
type ClassPublicPropsRes = ClassPublicProps<Xie>